<?php
/**
 * AccountController communicates with other applications.
 * Applications can request authentication, get user information ...
 * @package Account
 * @author Urban Soban
 * @version 0.1a
 * @copyright 2009 Urban Soban
 * @link http://masterplan.sobanu.net
 */

class AccountController extends ApplicationController {
	protected $AppName = "account";
	protected $IncludeFiles = array("account.class.php", "access.class.php");
	protected $HeadTags = array("<link rel=\"stylesheet\" type=\"text/css\" href=\"{\$env.url}lib/account/views/account.css\" />",
								"<script type=\"text/javascript\" src=\"{\$env.url}lib/account/account.js\"></script>");
	protected $UseApps = array(array("name" => "mysql"), array("name" => "phpmailer"), array("name" => "flags"), array("name" => "redirector"));

	/**
	 * Holds current active instance of Account
	 * Loaded from session or freshly created (empty)
	 *
	 * @var Account
	 */
	private $Account;

	function init(){
		/* If user is already logged in, instance of Account is present in session, so
			we load and unserialize it
		*/
		$this->isLogged();

		$HTTP = new HTTPRequest();
		$URLPosition = SystemRegistry::getInstance()->get("url_position");

		$URLParameterOne = $HTTP->get($URLPosition);

		switch ($URLParameterOne){
			/* Handle login */
			case "login":
				$this->ViewFile = "login.tpl";
				if(isset($_POST["login"])){
					if($this->login() == true){
						if(isset($_SESSION["fms_redirect"])){
							$Redirector = $this->UseApps["redirector"];
							$Redirector->redirect($_SESSION["fms_redirect"]);
						}

						$this->ViewFile = "message.tpl";
						return $this->Language->get("login_success");
					}
				}
			break;
			/* Handle register */
			case "register":
				$this->ViewFile = "register.tpl";
				if(isset($_POST["register"])){
					if($this->register() == true){
						$this->ViewFile = "message.tpl";
						return $this->Language->get("create_success");
					}
				}
			break;
			/* Handle activation */
			case "activate":
				$this->ViewFile = "message.tpl";

				$URLParameterAccountID = $HTTP->get($URLPosition+1);
				$URLParameterSecretKey = $HTTP->get($URLPosition+2);

				if(is_numeric($URLParameterAccountID) && is_numeric($URLParameterSecretKey)){
					if($this->activate($URLParameterAccountID, $URLParameterSecretKey) == true){
						return $this->Language->get("activate_success");
					}
				}
			break;
			/* Handle forgotten passwords */
			case "forgot-password":
				$this->ViewFile = "forgot.tpl";
				if(isset($_POST["forgot"])){
					if($this->forgot() == true){
						$this->ViewFile = "message.tpl";
						return $this->Language->get("check_email_for_pass");
					}
				}
			break;

			/* Handle logout request */
			case "logout":
				$this->ViewFile = "message.tpl";
				if($this->logout() == true){
					return $this->Language->get("logout_success");
				}
			break;

		}

		if($this->Status != 0){
			$this->ViewFile = "message.tpl";
			return $this->ErrorInfo;
		}
		/* If user didn't request any of actions above, return AccountController */
		return $this;
	}

	/**
	 * Creates new user
	 * Reads data from $_POST, therefore can only be used by user through GET/POST request, not by other applications.
	 *
	 * @return boolean
	 */
	function register(){
		// Check if any required field is empty
		if(empty($_POST["username"]) || empty($_POST["password"]) || empty($_POST["email"]) || empty($_POST["re_password"]) || !isset($_POST["agree_tos"])){
			$this->Status = 110;
			$this->ErrorInfo = $this->Language->get("fill_required_fields");
			return false;
		}

		// Get and escape username
		$Username = escape($_POST["username"], $this->UseApps["mysql"]);		// get username

		// Get email and check if it is valid
		if(!isEmail($_POST["email"])){
			$this->Status = 110;
			$this->ErrorInfo = $this->Language->get("enter_valid_email");
			return false;
		}
		$Email = $_POST["email"];

		// Get password and re-password, hash them and check if they are equal
		$Password = md5($_POST["password"]);
		$Re_Password = md5($_POST["re_password"]);
		if($Password != $Re_Password){
			$this->Status = 111;
			$this->ErrorInfo = $this->Language->get("passwords_dont_match");
			return false;
		}

		// Check if user already exists
		if($this->getUserData($Username) != false){
			$this->Status = 112;
			$this->ErrorInfo = $this->Language->get("account_exists");
			return false;
		}

		// if not, insert new user
		$MySQL = $this->UseApps["mysql"];

		$NewAccount = new Account($MySQL);
		if($NewAccount->updateAccount($Username, $Password, $Email, 0, false)){

			// if account has been successfully created, send email with activation link.
			$Mailer = $this->UseApps["phpmailer"];

			$PageURL = Core::$FMSConfig->getValue("environment", "url");
			$PageTitle = Core::$FMSConfig->getValue("environment", "page_title");

			$MailBody = "<strong>Hello $Username!</strong>\n<br />
					You have created new account at $PageURL. You account needs to be activated.\n\n<br /><br />
					In order to activate it, please click or copy the following link: <a href=\"{$PageURL}account/activate/{$NewAccount->getID()}/{$NewAccount->getSecretKey()}/\">{$PageURL}account/activate/{$NewAccount->getID()}/{$NewAccount->getSecretKey()}/</a>\n\n<br /><br />
					Once your account is activated, you will be able to use all page features.\n\n<br /><br />
					Have a good time,\n<br />$PageTitle team";

			if($Mailer->sendMail($NewAccount->getEmail(), $MailBody, "Account activation") == false){
				$this->Status = 112;
				$this->ErrorInfo = $Mailer->getError();
				return false;
			}
			else {
				return true;
			}
		}
		else {
			return false;
		}
	}

	/**
	 * Activates account with given ID number
	 *
	 * @param int $account_id
	 * @param int $account_secret_key
	 * @return boolean
	 */
	function activate($account_id, $account_secret_key){
		$ActivateAccount = new Account($this->UseApps["mysql"]);


		if($ActivateAccount->loadData($account_id) == false){
			$this->Status = 116;
			$this->ErrorInfo = $this->Language->get("account_doesnt_exist");
			return false;
		}

		$AccountSecretKey = $ActivateAccount->getSecretKey();

		if($AccountSecretKey == $account_secret_key){
			if($ActivateAccount->updateAccount($ActivateAccount->getUsername(), null, null, null, "true") == true){
				return true;
			}
			else {
				$this->Status = 117;
				$this->ErrorInfo = "Error updating database.";
				return false;
			}
		}
		else {
			$this->Status = 118;
			$this->ErrorInfo = $this->Language->get("invalid_activation_key");
			return false;
		}
	}

	/**
	 * Returns Account object with all user information
	 *
	 * @param int/string $usernameOrID ID (int) or username (string)
	 * @return Account/boolean Account on success, false if account doesn't exist
	 */
	function getUserData($usernameOrID){
		$Account = new Account($this->UseApps["mysql"], $usernameOrID);

		if($Account->getID() == null){
			return false;
		}

		return $Account;
	}

	function login(){
	session_regenerate_id();	// Regenerate user ID at every login, security reasons

		if(empty($_POST["username"]) || empty($_POST["password"])){
			$this->Status = 120;
			$this->ErrorInfo = $this->Language->get("enter_username_password");
			return false;
		}

		/* Load user data and check password */
		$Username = escape($_POST["username"], $this->UseApps["mysql"]);
		$Password = md5($_POST["password"]);

		$LoginAccount = $this->getUserData($Username);
		if($LoginAccount == false){
			$this->Status = 121;
			$this->ErrorInfo = $this->Language->get("account_username_doesnt_exist");
			return false;
		}
		else {
			if($LoginAccount->isActivated() != true){
				$this->Status = 123;
				$this->ErrorInfo = $this->Language->get("account_not_activated");
				return false;
			}

			if($LoginAccount->getPassword() != $Password){
				$this->Status = 122;
				$this->ErrorInfo = $this->Language->get("incorrect_password");
				return false;
			}

			$this->Account = $LoginAccount;
			$_SESSION["fms_account"] = serialize($LoginAccount);
			return true;
		}
	}

	/**
	 * Destroys Account object which serialized in session.
	 *
	 * @return boolean
	 */
	function logout(){
		if(!$this->isLogged()){
			$this->Status = 123;
			$this->ErrorInfo = $this->Language->get("not_logged_in");
			return false;
		}

		unset($_SESSION["fms_account"]);
		return true;
	}

	/**
	 * Generates new password and sends it to user's e-mail.
	 *
	 * @return boolean
	 */
	function forgot(){
		$Username = escape($_POST["username"], $this->UseApps["mysql"]);

		$ForgotAccount = $this->getUserData($Username);

		if($ForgotAccount == false){
			$this->Status = 124;
			$this->ErrorInfo = $this->Language->get("account_username_doesnt_exist");
			return false;
		}

		/* Generate new password and update account */
		$NewPassword = rand(00000001, 99999999);

		$ForgotAccount->updateAccount($Username, md5($NewPassword));

		/* Send e-mail */
		$Mailer = $this->UseApps["phpmailer"];

		$PageTitle = Core::$FMSConfig->getValue("environment", "page_title");
		$MailBody = "<strong>Hello $Username!</strong>\n<br />
					You have requested new password. Your new password is: <strong>$NewPassword</strong>\n\n<br /><br />
					Now you are prepared to login.\n\n<br /><br />
					Have a good time,\n<br />$PageTitle team";

		if($Mailer->sendMail($ForgotAccount->getEmail(), $MailBody, "New password") == false){
			$this->Status = 125;
			$this->ErrorInfo = $Mailer->getError();
			return false;
		}

		return true;
	}

	/**
	 * Checks if user is logged in
	 * If Account object is present in session, it is unserialized
	 *
	 * @return boolean
	 */
	function isLogged(){
		if($this->Account != null){
			return true;
		}
		elseif(isset($_SESSION["fms_account"])){
			$Object = unserialize($_SESSION["fms_account"]);

			if($Object instanceof Account){
				$this->Account = $Object;
				return true;
			}

			return false;
		}

		return false;
	}

	/**
	 * Checks if user can access given application
	 *
	 * @param string $app_name
	 * @return boolean
	 */
	function canAccess($app_name){
		if(!$this->isLogged()){
			return false;
		}

		$Access = new Access($this->Account, $this->UseApps["mysql"]);

		if($Access->canAccess($app_name) == true){
			return true;
		}

		return false;
	}

	/**
	 * Retuns current Account instance (if present)
	 *
	 * @return Account/boolean Account if user is logged in, false if not
	 */
	function getAccount(){
		if($this->isLogged()){
			return $this->Account;
		}

		return false;
	}
}

?>